package org.example.common.utils;

import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

@Slf4j
public class JwtUtils {
    //有效期为
    public static final Long JWT_TTL = 1000L*60*60;// 5 * 60 *1000  5分钟
    //设置秘钥明文
    public static final String JWT_KEY = "development-fast";

    public static String getUUID(){
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 核心方法，通过配置获取 jwt 构造器
     * @param subject token中要存放的数据（json格式）
     * @param ttlMillis 过期时间
     * @param uuid token 唯一标识
     * @return  配置好的 jwt-token 构造器
     */
    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if(Objects.isNull(ttlMillis)){
            ttlMillis=JwtUtils.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)                //唯一的ID
                .setSubject(subject)        // 主题  可以是JSON数据
                .setIssuer("sg")            // 签发者
                .setIssuedAt(now)           // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);    // 过期时间
    }

    /**
     * 生成 jwt-token
     * @param subject token中要存放的数据（json格式）
     * @return jwt-token 字符串
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间
        return builder.compact();
    }

    /**
     * 以工具类内部的 uuid 生成器生成的 uuid 作为 token 的唯一标识，生成 jwt-token
     * @param subject token中要存放的数据（json格式）
     * @param ttlMillis token超时时间
     * @return jwt-token 字符串
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间
        return builder.compact();
    }

    /**
     * 以外界传入的 id 作为 token 的唯一标识，生成 jwt-token
     * @param id 自定义 token 唯一标识
     * @param subject 令牌所有者
     * @param ttlMillis jwt过期时间
     * @return jwt 字符串
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
        return builder.compact();
    }

    /**
     * 生成加密后的秘钥 secretKey
     * @return 加密密钥
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(JwtUtils.JWT_KEY.getBytes());
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 验证解析 jwt ，获取声明
     *
     * @param jwt 用户传入的需要验证的 jwt
     * @return 声明（ jwt 内保存的内容）
     */
    public static Claims parseJWT(String jwt) throws ExpiredJwtException {
        SecretKey secretKey = generalKey();
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        }
        catch (ExpiredJwtException e) {
            log.error(e.getMessage());
        }
        return claims;
    }

}
